/*
  Sensuino
 
 Sensornet signal processing module.

 Created 18 July 2010
 By Manu Montejo

|---- loop()
  |-- update frequencies
  |-- acq loop
        |-- generate sound message (n-times)

 
http://sensornetpilot.blogspot.com
 */

// CONFIGURATION

// -- timing ---
const long INPUT_SAMPLING_RATE   =   4;  //seconds
const long OUTPUT_SAMPLING_RATE  =  4;  //seconds  


// --- range ---
const long MIN_VOLTAGE      =  100L;  // 0.5 Volts
const long MAX_VOLTAGE      =  620L;  // 3.0 Volts 

const long SLOT_PERIOD    =200L;  //millis  
const int START_FREQUENCY  = 3500;  // frequency of the start bit
const int BUFFER_LENGTH   = 100;  //Size of the buffer
const int FREQUENCY_LENGTH=   6;  //Number of frequencies in the sound message


// INPUT/OUPUT  
int  ledPin       = 13;    // LED connected to digital pin 13
int  digitalOut   = 12;
int  analogInput  =  1;

// INTERNAL VARIABLES
int buffer[BUFFER_LENGTH]; // This buffer stores voltage analog input values
int bufferCounter  = 0;    // The index of last value added to the buffer
int frequencies[FREQUENCY_LENGTH]; // The array of frequencies for the sound message

// DISCRETE FREQUENCIES TABLE
int discreteFrequenciesTable[200]; // The array of the discrete output frequencies
const float  DF_RANGES[]  = {500, 1200, 1700, 2000, 2200, 3400}; // define the freq intervals
const float  DF_LEVELS[]  = {  8,    5,    4,    3,    2}; // define the number of levels in 100Hz in each interval
const int    DF_NUMBER_INTERVALS = 6; // size of DF_RANGES array
int          DF_SIZE;  // number of discrete frequencies

// FREQUENCIES RANGE (linear scaling)
const long MIN_FREQUENCY    =  500L;  // minimum 
const long MAX_FREQUENCY    = 3400L;  //

long nAcq;        // number of acquisition in each loop
long nMessages;   // number of messages between each acq
long messageSeparatorSilence; // silence duration (millis) between messages to have an integer number of messages between each acq

// TEST VARIABLES
int testVoltage = 0;


// The setup() method runs once, when the sketch starts
void setup()   {                
  // Boot message
  Serial.begin(9600);
  Serial.println("sensuino version 1.0/build 20101020");

  // initialize the digital pin as an output:
  pinMode(ledPin, OUTPUT);
  pinMode(digitalOut, OUTPUT);
  
  // initialization
  nAcq = OUTPUT_SAMPLING_RATE / INPUT_SAMPLING_RATE;
  double messageDuration = (FREQUENCY_LENGTH +1) * (SLOT_PERIOD + SLOT_PERIOD/10);
  nMessages = INPUT_SAMPLING_RATE*1000.0/messageDuration;
  
  double silenceSeparatorDuration = INPUT_SAMPLING_RATE*1000.0 - nMessages * messageDuration;
  messageSeparatorSilence = silenceSeparatorDuration / nMessages;
  
  
  if (nAcq <1) nAcq = 1;
  if (nMessages <1) nMessages = 1;
  for (int i=0; i < FREQUENCY_LENGTH; i++){
    frequencies[i] = MIN_FREQUENCY;
  }
  generateDiscreteFrequency();


//--------- info
  Serial.print("Sampling rates(seconds): input="); Serial.print(INPUT_SAMPLING_RATE); Serial.print(" output="); Serial.println(OUTPUT_SAMPLING_RATE); 
  Serial.print("Acq/loop="); Serial.print(nAcq); Serial.print(" messages/acq="); Serial.print(nMessages); Serial.print(" messageDuration="); Serial.println(messageDuration); 
  Serial.print(" silence (in each acq)="); Serial.println(messageSeparatorSilence); 

  Serial.println("Discrete table of frequencies");
  Serial.print("Freq range intervals:");
  for (int i=0; i<DF_NUMBER_INTERVALS-1; i++){
    Serial.print(" "); Serial.print(DF_RANGES[i]); Serial.print( "  (" );Serial.print( DF_LEVELS[i] ); Serial.print( ")  " );
  }
  Serial.println(DF_RANGES[DF_NUMBER_INTERVALS-1] );
  Serial.print(" # frequencies:"); Serial.print(DF_SIZE); Serial.print( " Hz min=");Serial.print(discreteFrequenciesTable[0]);
  Serial.print( " max=");Serial.println(discreteFrequenciesTable[DF_SIZE-1]);
  
  Serial.print("Voltage MIN:"); Serial.print(MIN_VOLTAGE); Serial.print("u "); Serial.print(MIN_VOLTAGE*5000.0/1023);Serial.print(" mV ");
  Serial.print(" MAX:"); Serial.print(MAX_VOLTAGE); Serial.print("u "); Serial.print(MAX_VOLTAGE*5000.0/1023);Serial.println(" mV ");
 
  Serial.println("---------------------------------------------------");

//--------- debug

  for (int i=MIN_VOLTAGE-10; i < MAX_VOLTAGE+10; i++){
    int f = voltage2DiscreteFrequency(i);
    double v = i *5000.0/1023;
    Serial.print("input:"); Serial.print(i); Serial.print(" freq:"); Serial.print(f);Serial.print(" mV:"); Serial.println(v);
  }
//Serial.print(" discreteFrequenciesTable:-1"); Serial.println(discreteFrequenciesTable[DF_SIZE-1]);
//Serial.print(" discreteFrequenciesTable:"); Serial.println(discreteFrequenciesTable[DF_SIZE]);
//Serial.print(" discreteFrequenciesTable:+1"); Serial.println(discreteFrequenciesTable[DF_SIZE+1]);

}


// the loop() method runs over and over again,
// as long as the Arduino has power
void loop(){
  // calculate mean value
  calculateFrequencies(); // -> frequencies
  // acq loop
  int i =0;
  do {
    acquisition(); // -> buffer
    // generate the sound signal
    for (int j=0; j<nMessages; j++) {
      generateAmplitudeMessage();
    }
    i++;
  } while (i<nAcq);
}

void generateAmplitudeMessage(){
  long silence_duration = SLOT_PERIOD/10;
  
  // start bit
  noTone(digitalOut); tone(digitalOut, START_FREQUENCY); delay(SLOT_PERIOD);  
  noTone(digitalOut); delay(silence_duration);

//Serial.print("generateMessage: silence");  Serial.print(silence_duration);
  
  // value bits
  for (int i=0; i < FREQUENCY_LENGTH; i++){
    int frequency = frequencies[i];
    noTone(digitalOut); tone(digitalOut, frequency); delay(SLOT_PERIOD);  
    noTone(digitalOut); delay(silence_duration);

//Serial.print(" f=");  Serial.print(frequency);
  }
//Serial.println(" ");
}


// Functions

int voltage2Frequency(int voltage){
  // encode the voltate into a frequency
  if (voltage < MIN_VOLTAGE) voltage = MIN_VOLTAGE;
  if (voltage > MAX_VOLTAGE) voltage = MAX_VOLTAGE;

//long value;
//value = MAX_FREQUENCY * (voltage - MIN_VOLTAGE);
//Serial.print("MAX_FREQUENCY * (voltage - MIN_VOLTAGE) = "); Serial.println(value);
//value =  MIN_FREQUENCY + value / (MAX_VOLTAGE-MIN_VOLTAGE);
//Serial.print("MIN_FREQUENCY + value / (MAX_VOLTAGE-MIN_VOLTAGE) = "); Serial.println(value);
//value =  MIN_FREQUENCY + MAX_FREQUENCY * (voltage - MIN_VOLTAGE) / (MAX_VOLTAGE-MIN_VOLTAGE);
//Serial.print("value = "); Serial.println(value);

  long frequency = (MAX_FREQUENCY-MIN_FREQUENCY) * (voltage - MIN_VOLTAGE);
  frequency = MIN_FREQUENCY + frequency / (MAX_VOLTAGE-MIN_VOLTAGE);
Serial.print("voltage2Frequency: v="); Serial.print(voltage);  Serial.print(" freq=");   Serial.println(frequency);  
  return frequency;
}

int voltage2DiscreteFrequency(int voltage){
  // out of the limits returns the min-max freq value
  if (voltage <= MIN_VOLTAGE) 
    return DF_RANGES[0];
  if (voltage >= MAX_VOLTAGE) 
    return DF_RANGES[DF_NUMBER_INTERVALS-1];
  // within the limits
  int frequency_index = (DF_SIZE -0) * (voltage - MIN_VOLTAGE) / (MAX_VOLTAGE-MIN_VOLTAGE);
  int freq = discreteFrequenciesTable[frequency_index];
  return freq;
}

void generateDiscreteFrequency(){
  int counter = 0;
  float currentF = DF_RANGES[0];
  for (int i=0; i < DF_NUMBER_INTERVALS-1; i++){
    int f_increment =  100.0/DF_LEVELS[i] ;
    currentF = currentF + f_increment;
//    Serial.print("f_increment:");Serial.println(f_increment);
    float maxF = DF_RANGES[i+1];
    while (currentF<=maxF) {
      discreteFrequenciesTable[counter] = currentF;
      counter++;
      currentF = currentF + f_increment;
    };
  }
  DF_SIZE = counter;
}

void calculateFrequencies(){
// adds the last mean value and updates the list of frequencies
  
  int fs[FREQUENCY_LENGTH];
  // add latest mean value 
  int voltage = calculateMeanVoltage();
  //int freq = voltage2Frequency(voltage);
  int freq = voltage2DiscreteFrequency(voltage);
  fs[0] = freq;
  
  // add the remaing values
  for (int i=1; i < FREQUENCY_LENGTH; i++){
    int f = frequencies[i-1];
    fs[i] = f;
  }
  // copy values to frequencies array
  for (int i=0; i < FREQUENCY_LENGTH; i++){
    frequencies[i] = fs[i];
  }
  
}


int calculateMeanVoltage(){
// Returns the mean value of the voltage buffer and resets the buffer
  
//------------debug--------------
//  Serial.print("calculateFrequency:buffer=[");
//  for (int i=0; i<20; i++) {
//    Serial.print(buffer[i]); Serial.print(",");
//  }
//  Serial.println("...");

  // calculate the average value
  int voltage = 0;
  for (int i=0; i<bufferCounter; i++) {
    voltage = voltage + buffer[i];
  }
  voltage = voltage/bufferCounter;

//test:---increase step
  testVoltage = testVoltage + 4;
  if (testVoltage < MIN_VOLTAGE) testVoltage = MIN_VOLTAGE;
  if (testVoltage > MAX_VOLTAGE) testVoltage = MIN_VOLTAGE;
  voltage = testVoltage;

  // reset the buffer
  bufferCounter=0;
  return voltage;
}

void acquisition()
{
  int voltage = analogRead(analogInput); //0-1023 : 0-5V
//---dummy  
voltage = random(0, 1023) ;

  add2Buffer(voltage);

//------------debug--------------
//Serial.print("debug:acq:v= ");
//Serial.print(voltage);Serial.print(" units:"); Serial.print(voltage*5.000/1023);Serial.println(" volts");

}

void add2Buffer(int v){
  if (bufferCounter > BUFFER_LENGTH - 1) bufferCounter = 0; //
  buffer[bufferCounter] = v;
  bufferCounter++;
}

